package de.wz.schwimmen;

import static de.wz.schwimmen.Config.ACTIVITY_REQUEST_CODE_PAYMENT;
import static de.wz.schwimmen.Config.NUM_PLAYER;
import static de.wz.schwimmen.StaticDataStorage.ALLOWED_RANKING_3PLAYER;
import static de.wz.schwimmen.StaticDataStorage.ALLOWED_RANKING_4PLAYER;
import static de.wz.schwimmen.StaticDataStorage.CHECK_BOX_PLAYER;
import static de.wz.schwimmen.StaticDataStorage.LABEL_NAME;
import static de.wz.schwimmen.StaticDataStorage.LABEL_RANK;
import static de.wz.schwimmen.StaticDataStorage.TEXT_VIEW_AMOUNT;
import static de.wz.schwimmen.StaticDataStorage.TEXT_VIEW_COUNT;
import static de.wz.schwimmen.StaticDataStorage.TEXT_VIEW_NAME;
import static de.wz.schwimmen.StaticDataStorage.TEXT_VIEW_NEW_ACC_BALANCE;
import static de.wz.schwimmen.StaticDataStorage.TEXT_VIEW_OLD_ACC_BALANCE;
import static de.wz.schwimmen.StaticDataStorage.TEXT_VIEW_PAYMENT;
import static de.wz.schwimmen.StaticDataStorage.TEXT_VIEW_SUM;
import static de.wz.schwimmen.StaticDataStorage.TOGGLE_BUTTONS_PLAYER;
import static de.wz.schwimmen.StaticDataStorage.TOGGLE_BUTTONS_RANK;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;

/**
 * @author Peter Eimann
 */
public class SpielActivity extends Activity implements OnClickListener {

	private SharedPreferences preferences;
	private Status status;

	private boolean restart;
	private boolean[] playerPresent = new boolean[NUM_PLAYER];
	private int numberOfPlayerPresent;
	private int gameCounter;
	private int currentPlayer;
	private int[][] rankCounter = new int[NUM_PLAYER][NUM_PLAYER];
	private double[][] rankAmounts = new double[NUM_PLAYER][NUM_PLAYER];
	private double[] sumAmounts = new double[NUM_PLAYER];
	private double[] payAmounts = new double[NUM_PLAYER];
	private double[] payments = new double[NUM_PLAYER];
	private double[] oldAccountBalances = new double[NUM_PLAYER];
	private double[] newAccountBalances = new double[NUM_PLAYER];
	private List<int[]> history = new ArrayList<int[]>();
	private String[] points;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread paramThread, Throwable exception) {
                StringWriter stackTrace = new StringWriter();
                exception.printStackTrace(new PrintWriter(stackTrace));

                StringBuilder errormessage = new StringBuilder(exception.getMessage());
            	while (exception.getCause() != null) {
            		exception = exception.getCause();
            		errormessage.append("\n\t\t- ").append(exception.getMessage());
            	}

                Intent spielIntent = new Intent(SpielActivity.this, SpielActivity.class);
                spielIntent.putExtra("de.wz.schwimmen.errormessage", errormessage.toString());
                spielIntent.putExtra("de.wz.schwimmen.stacktrace", stackTrace.toString());
                spielIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
                spielIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                startActivity(spielIntent);
                System.exit(0);
            }
        });

		setContentView(R.layout.main);
		PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
		points = getResources().getStringArray(R.array.points);

		initializeView();

		getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
	}

	@Override
	public void onStart() {
		super.onStart();
		preferences = PreferenceManager.getDefaultSharedPreferences(this);

		String errorMessage = getIntent().getStringExtra("de.wz.schwimmen.errormessage");
		TextView errorMessageView = findViewById(R.id.textViewErrorMessage, TextView.class);
		if (errorMessage != null) {
			errorMessageView.setText(getResources().getString(R.string.text_errorMessage, errorMessage));
		} else {
			errorMessageView.setText("");
		}

		String stackTrace = getIntent().getStringExtra("de.wz.schwimmen.stacktrace");
		TextView stackTraceView = findViewById(R.id.textViewStackTrace, TextView.class);
		if (stackTrace != null) {
			stackTraceView.setText(getResources().getString(R.string.text_stackTrace, stackTrace));
		} else {
			stackTraceView.setText("");
		}
	}

	@Override
	protected void onStop() {
	    super.onStop();
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
			case R.id.buttonNewGame:
				handleButtonNewGame();
				break;
			case R.id.buttonCalculate:
				handleButtonCalculate();
				break;
			case R.id.buttonPayment:
				handleButtonPayment();
				break;
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.options_menu, menu);

		return true;
	}

	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		switch (status) {
			case INIT:
				menu.findItem(R.id.menu_game_start).setEnabled(true);
				menu.findItem(R.id.menu_game_history).setEnabled(false);
				menu.findItem(R.id.menu_game_delete).setEnabled(false);
				menu.findItem(R.id.menu_game_export).setEnabled(false);
				menu.findItem(R.id.menu_game_save).setEnabled(false);
				menu.findItem(R.id.menu_game_restore).setEnabled(true);
				break;
			case STARTED:
				menu.findItem(R.id.menu_game_start).setEnabled(false);
				menu.findItem(R.id.menu_game_history).setEnabled(gameCounter > 0 ? true : false);
				menu.findItem(R.id.menu_game_delete).setEnabled(gameCounter > 0 ? true : false);
				menu.findItem(R.id.menu_game_export).setEnabled(false);
				menu.findItem(R.id.menu_game_save).setEnabled(false);
				menu.findItem(R.id.menu_game_restore).setEnabled(true);
				break;
			case CALCULATE:
				menu.findItem(R.id.menu_game_start).setEnabled(false);
				menu.findItem(R.id.menu_game_history).setEnabled(false);
				menu.findItem(R.id.menu_game_delete).setEnabled(false);
				menu.findItem(R.id.menu_game_export).setEnabled(false);
				menu.findItem(R.id.menu_game_save).setEnabled(false);
				menu.findItem(R.id.menu_game_restore).setEnabled(true);
				break;
			case PAYMENT:
				menu.findItem(R.id.menu_game_start).setEnabled(true);
				menu.findItem(R.id.menu_game_history).setEnabled(false);
				menu.findItem(R.id.menu_game_delete).setEnabled(false);
				menu.findItem(R.id.menu_game_export).setEnabled(true);
				menu.findItem(R.id.menu_game_save).setEnabled(true);
				menu.findItem(R.id.menu_game_restore).setEnabled(false);
				break;
			case SAVED:
				menu.findItem(R.id.menu_game_start).setEnabled(true);
				menu.findItem(R.id.menu_game_history).setEnabled(false);
				menu.findItem(R.id.menu_game_delete).setEnabled(false);
				menu.findItem(R.id.menu_game_export).setEnabled(true);
				menu.findItem(R.id.menu_game_save).setEnabled(false);
				menu.findItem(R.id.menu_game_restore).setEnabled(false);
				break;
		}

		return true;
	}

	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
			case R.id.menu_game_start:
				handleMenuStart();
				break;
			case R.id.menu_game_history:
				handleMenuHistory();
				break;
			case R.id.menu_game_export:
				handleMenuExportResult();
				break;
			case R.id.menu_game_delete:
				handleMenuDelete();
				break;
			case R.id.menu_game_save:
				handleMenuSaveBalance();
				break;
			case R.id.menu_game_restore:
				handleMenuRestore();
				break;
			case R.id.menu_settings:
	            startActivity(new Intent(this, PreferenceActivity.class));
				break;
		}

		return true;
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent sender) {
		super.onActivityResult(requestCode, resultCode, sender);

		if (sender != null) {
			if (requestCode == ACTIVITY_REQUEST_CODE_PAYMENT) {
				handleActivityResultForPayment(resultCode, sender);
			}
		}
	}

	private void initializeView() {
		Button buttonNewGame = findViewById(R.id.buttonNewGame, Button.class);
		buttonNewGame.setOnClickListener(this);
		buttonNewGame.setEnabled(false);

		Button buttonCalculate = findViewById(R.id.buttonCalculate, Button.class);
		buttonCalculate.setOnClickListener(this);
		buttonCalculate.setEnabled(false);

		Button buttonPayment = findViewById(R.id.buttonPayment, Button.class);
		buttonPayment.setOnClickListener(this);
		buttonPayment.setEnabled(false);

		setToggleButtons(false, false, false, false);
		rewriteToggleButtons();
		
		status = Status.INIT;
	}

	@Override
	public void onBackPressed() {
		AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
		alertDialogBuilder.setTitle(getResources().getString(R.string.alert_exit_title));
		alertDialogBuilder.setMessage(getResources().getString(R.string.alert_exit_message));
		alertDialogBuilder.setCancelable(false);
		alertDialogBuilder.setPositiveButton(getResources().getString(R.string.label_yes), 
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
					SpielActivity.super.onBackPressed();
				}
			});
		alertDialogBuilder.setNegativeButton(getResources().getString(R.string.label_no),
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
				}
			});

		AlertDialog alertDialog = alertDialogBuilder.create();
		alertDialog.show();
	}

	private void handleMenuStart() {
		if (restart) {
			AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
			alertDialogBuilder.setTitle(getResources().getString(R.string.alert_restart_title));
			alertDialogBuilder.setMessage(getResources().getString(R.string.alert_restart_message));
			alertDialogBuilder.setCancelable(false);
			alertDialogBuilder.setPositiveButton(getResources().getString(R.string.label_yes), 
				new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int id) {
						dialog.cancel();
						restart = false;
						performStart();
					}
				});
			alertDialogBuilder.setNegativeButton(getResources().getString(R.string.label_no),
				new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int id) {
						dialog.cancel();
					}
				});

			AlertDialog alertDialog = alertDialogBuilder.create();
			alertDialog.show();
		} else {
			performStart();
		}
	}

	private void handleButtonNewGame() {
		if (!isCorrectRanking()) {
			return;
		} else {
			gameCounter++;
		}

		int historyItem[] = new int[NUM_PLAYER];
		for (int player = 0; player < NUM_PLAYER; player++) {
			if (playerPresent[player]) {
				for (int rank = 0; rank < NUM_PLAYER; rank++) {
					if (findViewById(TOGGLE_BUTTONS_PLAYER[player][rank], ToggleButton.class).isChecked()) {
						findViewById(TOGGLE_BUTTONS_PLAYER[player][rank] ,ToggleButton.class).setChecked(false);
						rankCounter[player][rank]++;
						historyItem[player] = rank + 1;
						break;
					}
				}
				incrementCounter(TEXT_VIEW_SUM[player]);
			}
		}
 		history.add(historyItem);

		rewriteToggleButtons();

		if (gameCounter >= getIntPreference("pref_key_num_games")) {
			findViewById(R.id.buttonNewGame).setEnabled(false);
			for (int player = 0; player < NUM_PLAYER; player++) {
				findViewById(TEXT_VIEW_NAME[player], TextView.class).setTextColor(Color.WHITE);
			}
		} else {
			selectNextMerger();
		}

		preferences.edit().putString("pref_key_restore", createRestoreString()).apply();
	}

	private void handleButtonCalculate() {
		if (gameCounter < getIntPreference("pref_key_num_games")) {
			AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
			alertDialogBuilder.setTitle(getResources().getString(R.string.alert_calculate_title));
			alertDialogBuilder.setMessage(getResources().getString(R.string.alert_calculate_message));
			alertDialogBuilder.setCancelable(false);
			alertDialogBuilder.setPositiveButton(getResources().getString(R.string.label_yes), 
				new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int id) {
						dialog.cancel();
						performCalculate();
					}
				});
			alertDialogBuilder.setNegativeButton(getResources().getString(R.string.label_no),
				new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int id) {
						dialog.cancel();
					}
				});

			AlertDialog alertDialog = alertDialogBuilder.create();
			alertDialog.show();
		} else {
			performCalculate();
		}
	}

	private void handleButtonPayment() {
		Bundle basket = new Bundle();
		for (int player = 0; player < NUM_PLAYER; player++) {
			basket.putString("amount_player" + (player + 1), 
				findViewById(TEXT_VIEW_AMOUNT[player], TextView.class).getText().toString());
		}

		Intent payment = new Intent(this, PaymentActivity.class);
		payment.putExtras(basket);
		startActivityForResult(payment, ACTIVITY_REQUEST_CODE_PAYMENT);
	}

	private void handleMenuExportResult() {
		StringBuilder buf = new StringBuilder();
		for (int player = 0; player < NUM_PLAYER; player++) {
			buf.append(getResources().getString(LABEL_NAME[player]));
			buf.append(getResources().getString(R.string.export_separator));
			for (int rank = 0; rank < NUM_PLAYER; rank++) {
				buf.append(getResources().getString(R.string.export_rank, (rank + 1), rankCounter[player][rank],
					rankAmounts[player][rank]));
			}
			buf.append(getResources().getString(R.string.export_sum_amount, sumAmounts[player]));
			buf.append(getResources().getString(R.string.export_old_acc_balance, oldAccountBalances[player]));
			buf.append(getResources().getString(R.string.export_pay_amounts, payAmounts[player]));
			buf.append(getResources().getString(R.string.export_payments, payments[player]));
			buf.append(getResources().getString(R.string.export_new_acc_balance, newAccountBalances[player]));
		}

		Intent emailIntent = new Intent(Intent.ACTION_SENDTO);
		emailIntent.setType(Config.EMAIL_MSGTYPE);
		emailIntent.putExtra(Intent.EXTRA_SUBJECT, getResources().getString(R.string.text_subject));
		emailIntent.putExtra(Intent.EXTRA_TEXT, buf.toString());
		emailIntent.setData(Uri.parse(Config.EMAIL_RECIPIENT_PREFIX + getStringPreference("pref_key_email")));
		emailIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

	    try {
	        startActivity(Intent.createChooser(emailIntent, getResources().getString(R.string.text_chooseMailClient)));
	    } catch (android.content.ActivityNotFoundException ex) {
	        Toast.makeText(this, getResources().getString(R.string.text_noMailClient), Toast.LENGTH_LONG).show();
	    }
	}

	private void handleMenuDelete() {
		AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
		alertDialogBuilder.setTitle(getResources().getString(R.string.alert_delete_title));
		alertDialogBuilder.setMessage(getResources().getString(R.string.alert_delete_message));
		alertDialogBuilder.setCancelable(false);
		alertDialogBuilder.setPositiveButton(getResources().getString(R.string.label_yes), 
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
					performDelete();
				}
			});
		alertDialogBuilder.setNegativeButton(getResources().getString(R.string.label_no),
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
				}
			});

		AlertDialog alertDialog = alertDialogBuilder.create();
		alertDialog.show();
	}
	
	private void handleMenuHistory() {
		Bundle basket = new Bundle();
		for (int index = 0; index < history.size(); index++) {
			basket.putIntArray("history_item" + (index + 1), history.get(index));
		}

		Intent history = new Intent(this, HistoryActivity.class);
		history.putExtras(basket);
		startActivity(history);
	}

	private void handleMenuSaveBalance() {
		AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
		alertDialogBuilder.setTitle(getResources().getString(R.string.alert_save_balances_title));
		alertDialogBuilder.setMessage(getResources().getString(R.string.alert_save_balances_message));
		alertDialogBuilder.setCancelable(false);
		alertDialogBuilder.setPositiveButton(getResources().getString(R.string.label_yes), 
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
					performSaveBalance();
				}
			});
		alertDialogBuilder.setNegativeButton(getResources().getString(R.string.label_no),
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
				}
			});

		AlertDialog alertDialog = alertDialogBuilder.create();
		alertDialog.show();
	}

	private void handleMenuRestore() {
		AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
		alertDialogBuilder.setTitle(getResources().getString(R.string.alert_restore_title));
		alertDialogBuilder.setMessage(getResources().getString(R.string.alert_restore_message));
		alertDialogBuilder.setCancelable(false);
		alertDialogBuilder.setPositiveButton(getResources().getString(R.string.label_yes), 
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
					performRestore();
				}
			});
		alertDialogBuilder.setNegativeButton(getResources().getString(R.string.label_no),
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
				}
			});

		AlertDialog alertDialog = alertDialogBuilder.create();
		alertDialog.show();
	}
	
	private void handleActivityResultForPayment(int resultCode, Intent sender) {
		if (resultCode == RESULT_OK) {
			Bundle basket = sender.getExtras();
			status = Status.PAYMENT;
			for (int player = 0; player < NUM_PLAYER; player++) {
				try {
					payments[player] = Double.parseDouble(basket.getString("payment_player" + (player + 1)));
				} catch (Exception e) {
					status = Status.CALCULATE;
					break;
				}
				newAccountBalances[player] = payAmounts[player] - payments[player];

				findViewById(TEXT_VIEW_PAYMENT[player], TextView.class)
					.setText(getResources().getString(R.string.text_Amount, payments[player]));
				findViewById(TEXT_VIEW_NEW_ACC_BALANCE[player], TextView.class)
					.setText(getResources().getString(R.string.text_Amount, newAccountBalances[player]));

				if (newAccountBalances[player] < 0) {
					findViewById(TEXT_VIEW_NEW_ACC_BALANCE[player], TextView.class).setTextColor(Color.GREEN);
				} else if (newAccountBalances[player] > 0) {
					findViewById(TEXT_VIEW_NEW_ACC_BALANCE[player], TextView.class).setTextColor(Color.RED);
				} else {
					findViewById(TEXT_VIEW_NEW_ACC_BALANCE[player], TextView.class).setTextColor(Color.WHITE);
				}
			}
		}
	}

	private void performStart() {
		gameCounter = 0;
		numberOfPlayerPresent = 0;
		currentPlayer = 1;
		playerPresent = new boolean[NUM_PLAYER];
		rankCounter = new int[NUM_PLAYER][NUM_PLAYER];
		rankAmounts = new double[NUM_PLAYER][NUM_PLAYER];
		sumAmounts = new double[NUM_PLAYER];
		history.clear();
		preferences.edit().remove("pref_key_restore").apply();

		rewriteToggleButtons();
		resetCounter();

		findViewById(R.id.textViewErrorMessage, TextView.class).setText("");
		findViewById(R.id.textViewStackTrace, TextView.class).setText("");

		String startPlayer = getStringPreference("pref_key_player_1");
		for (int player = 0; player < NUM_PLAYER; player++) {
			if (findViewById(CHECK_BOX_PLAYER[player], CheckBox.class).isChecked()) {
				numberOfPlayerPresent++;
				playerPresent[player] = true;
				if (startPlayer.equals(findViewById(TEXT_VIEW_NAME[player], TextView.class).getText().toString())) {
					findViewById(TEXT_VIEW_NAME[player], TextView.class).setTextColor(Color.GREEN);
				} else {
					findViewById(TEXT_VIEW_NAME[player], TextView.class).setTextColor(Color.WHITE);
				}
			}
		}

		if (numberOfPlayerPresent < 3) {
			Toast.makeText(this, getResources().getString(R.string.text_checkPresence), Toast.LENGTH_LONG).show();
			return;
		}

		findViewById(R.id.buttonCalculate).setEnabled(true);
		findViewById(R.id.buttonNewGame).setEnabled(true);
		findViewById(R.id.buttonPayment).setEnabled(false);
		status = Status.STARTED;

		for (int id : CHECK_BOX_PLAYER) {
			findViewById(id).setEnabled(false);
		}

		setToggleButtons(playerPresent[0], playerPresent[1], playerPresent[2], playerPresent[3]);
	}

	private void performCalculate() {
		restart = true;

		setToggleButtons(false, false, false, false);
		findViewById(R.id.buttonCalculate).setEnabled(false);
		findViewById(R.id.buttonNewGame).setEnabled(false);
		findViewById(R.id.buttonPayment).setEnabled(true);
		status = Status.CALCULATE;

		for (int player = 0; player < NUM_PLAYER; player++) {
			findViewById(TEXT_VIEW_NAME[player], TextView.class).setTextColor(Color.WHITE);
			findViewById(CHECK_BOX_PLAYER[player]).setEnabled(true);
		}

		int[] prices = new int[4];
		if (numberOfPlayerPresent == 3) {
			prices[0] = getIntPreference("pref_key_amount_3player_rank1");
			prices[1] = getIntPreference("pref_key_amount_3player_rank2");
			prices[2] = getIntPreference("pref_key_amount_3player_rank3");
			prices[3] = 0;
		} else {
			prices[0] = getIntPreference("pref_key_amount_4player_rank1");
			prices[1] = getIntPreference("pref_key_amount_4player_rank2");
			prices[2] = getIntPreference("pref_key_amount_4player_rank3");
			prices[3] = getIntPreference("pref_key_amount_4player_rank4");
		}

		for (int player = 0; player < NUM_PLAYER; player++) {
			for (int rank = 0; rank < NUM_PLAYER; rank++) {
				rankAmounts[player][rank] = (double)(rankCounter[player][rank] * prices[rank]) / 100;
				sumAmounts[player] += rankAmounts[player][rank];
				oldAccountBalances[player] = getDoublePreference("pref_key_account_balance_player" + (player + 1));
			}
		}
		if (numberOfPlayerPresent == 3) {
			calculateAverage();
		}

		for (int player = 0; player < NUM_PLAYER; player++) {
			payAmounts[player] = sumAmounts[player] + oldAccountBalances[player];

			for (int rank = 0; rank < NUM_PLAYER && playerPresent[player]; rank++) {
				findViewById(TEXT_VIEW_COUNT[player][rank], TextView.class)
					.setText(getResources().getString(R.string.text_Amount, rankAmounts[player][rank]));
			}
			findViewById(TEXT_VIEW_SUM[player], TextView.class)
				.setText(getResources().getString(R.string.text_Amount, sumAmounts[player]));
			findViewById(TEXT_VIEW_OLD_ACC_BALANCE[player], TextView.class)
				.setText(getResources().getString(R.string.text_Amount, oldAccountBalances[player]));
			findViewById(TEXT_VIEW_AMOUNT[player], TextView.class)
				.setText(getResources().getString(R.string.text_Amount, payAmounts[player]));

			if (oldAccountBalances[player] < 0) {
				findViewById(TEXT_VIEW_OLD_ACC_BALANCE[player], TextView.class).setTextColor(Color.GREEN);
			} else if (oldAccountBalances[player] > 0) {
				findViewById(TEXT_VIEW_OLD_ACC_BALANCE[player], TextView.class).setTextColor(Color.RED);
			} else {
				findViewById(TEXT_VIEW_OLD_ACC_BALANCE[player], TextView.class).setTextColor(Color.WHITE);
			}
		}
	}

	private void performSaveBalance() {
		for (int player = 0; player < NUM_PLAYER; player++) {
			preferences.edit().putString("pref_key_account_balance_player" + (player + 1),
				Double.toString(newAccountBalances[player])).apply();
		}
        Toast.makeText(this, getResources().getString(R.string.text_balancesSaved), Toast.LENGTH_SHORT).show();
		findViewById(R.id.buttonPayment).setEnabled(false);
		status = Status.SAVED;
	}

	private void performDelete() {
		int[] lastRound = history.remove(history.size() - 1);

		for (int player = 0; player < NUM_PLAYER; player++) {
			if (playerPresent[player]) {
				for (int rank = 0; rank < NUM_PLAYER; rank++) {
					if (lastRound[player] == rank + 1) {
						rankCounter[player][rank]--;
						break;
					}
				}
				decrementCounter(TEXT_VIEW_SUM[player]);
			}
		}

		gameCounter--;
		selectPreviousMerger();
		rewriteToggleButtons();
		findViewById(R.id.buttonNewGame).setEnabled(true);
		preferences.edit().putString("pref_key_restore", createRestoreString()).apply();
		Toast.makeText(this, getResources().getString(R.string.text_deleted), Toast.LENGTH_SHORT).show();
	}

	private void performRestore() {
		String restoreString = preferences.getString("pref_key_restore", null);
		if (TextUtils.isEmpty(restoreString)) {
			Toast.makeText(this, getResources().getString(R.string.text_noRestoreData), Toast.LENGTH_SHORT).show();
			return;
		}

		parseRestoreString(restoreString);

		resetCounter();
		setToggleButtons(playerPresent[0], playerPresent[1], playerPresent[2], playerPresent[3]);
		rewriteToggleButtons();

		String nextMerger = getStringPreference("pref_key_player_" + currentPlayer);
		for (int player = 0; player < NUM_PLAYER; player++) {
			if (playerPresent[player]) {
				findViewById(TEXT_VIEW_SUM[player], TextView.class).setText(Integer.toString(gameCounter));
			}
			findViewById(CHECK_BOX_PLAYER[player], CheckBox.class).setChecked(playerPresent[player]);
			findViewById(CHECK_BOX_PLAYER[player], CheckBox.class).setEnabled(false);

			if (nextMerger.equals(getResources().getString(LABEL_NAME[player]))) {
				findViewById(TEXT_VIEW_NAME[player], TextView.class).setTextColor(Color.GREEN);
			} else {
				findViewById(TEXT_VIEW_NAME[player], TextView.class).setTextColor(Color.WHITE);
			}
		}

		findViewById(R.id.buttonCalculate).setEnabled(true);
		findViewById(R.id.buttonNewGame).setEnabled(true);
		findViewById(R.id.buttonPayment).setEnabled(false);
		status = Status.STARTED;
	}

	private void calculateAverage() {
		double[] sortedSumAmounts = {sumAmounts[0], sumAmounts[1], sumAmounts[2], sumAmounts[3]};
		Arrays.sort(sortedSumAmounts);
		double average = (sortedSumAmounts[3] * 3 + sortedSumAmounts[2] * 2 + sortedSumAmounts[1]) / 6;

		double remain = (average * 100) % 100;
		if (remain > 0 && remain < 50) {
			average = average + ((50 - remain) / 100);
		} else if (remain > 50) {
			average = average + ((100 - remain) / 100);
		}

		for (int player = 0; player < NUM_PLAYER; player++) {
			if (!playerPresent[player]) {
				sumAmounts[player] = average;
				break;
			}
		}
	}

	private void setToggleButtons(boolean player1, boolean player2, boolean player3, boolean player4) {
		for (int rank = 0; rank < 4; rank++) {
			findViewById(TOGGLE_BUTTONS_PLAYER[0][rank]).setEnabled(player1);
			findViewById(TOGGLE_BUTTONS_PLAYER[1][rank]).setEnabled(player2);
			findViewById(TOGGLE_BUTTONS_PLAYER[2][rank]).setEnabled(player3);
			findViewById(TOGGLE_BUTTONS_PLAYER[3][rank]).setEnabled(player4);
		}
		if (numberOfPlayerPresent == 3) {
			for (int player = 0; player < NUM_PLAYER; player++) {
				findViewById(TOGGLE_BUTTONS_RANK[3][player]).setEnabled(false);
			}
		}
	}

	private void incrementCounter(int id) {
		int value = Integer.parseInt(findViewById(id, TextView.class).getText().toString());
		findViewById(id, TextView.class).setText(Integer.toString(value + 1));
	}

	private void decrementCounter(int id) {
		int value = Integer.parseInt(findViewById(id, TextView.class).getText().toString());
		findViewById(id, TextView.class).setText(Integer.toString(value -1));
	}

	private void selectNextMerger() {
		if (currentPlayer == numberOfPlayerPresent) {
			currentPlayer = 1;
		} else {
			currentPlayer++;
		}
		String nextMerger = getStringPreference("pref_key_player_" + currentPlayer);

		for (int player = 0; player < NUM_PLAYER; player++) {
			if (nextMerger.equals(getResources().getString(LABEL_NAME[player]))) {
				findViewById(TEXT_VIEW_NAME[player], TextView.class).setTextColor(Color.GREEN);
			} else {
				findViewById(TEXT_VIEW_NAME[player], TextView.class).setTextColor(Color.WHITE);
			}
		}
	}

	private void selectPreviousMerger() {
		if (currentPlayer == 1) {
			currentPlayer = numberOfPlayerPresent;
		} else {
			currentPlayer--;
		}
		String nextMerger = getStringPreference("pref_key_player_" + currentPlayer);

		for (int player = 0; player < NUM_PLAYER; player++) {
			if (nextMerger.equals(getResources().getString(LABEL_NAME[player]))) {
				findViewById(TEXT_VIEW_NAME[player], TextView.class).setTextColor(Color.GREEN);
			} else {
				findViewById(TEXT_VIEW_NAME[player], TextView.class).setTextColor(Color.WHITE);
			}
		}
	}

	private boolean isCorrectRanking() {
		for (int player = 0; player < NUM_PLAYER; player++) {
			if (playerPresent[player] && getNumberOfButtonsPressed(TOGGLE_BUTTONS_PLAYER[player]) != 1) {
				Toast.makeText(this, getResources().getString(LABEL_NAME[player])
					+ getResources().getString(R.string.text_invalidRanking), Toast.LENGTH_LONG).show();
				return false;
			}
		}

		int rank1Pressed = getNumberOfButtonsPressed(TOGGLE_BUTTONS_RANK[0]);
		int rank2Pressed = getNumberOfButtonsPressed(TOGGLE_BUTTONS_RANK[1]);
		int rank3Pressed = getNumberOfButtonsPressed(TOGGLE_BUTTONS_RANK[2]);
		int rank4Pressed = getNumberOfButtonsPressed(TOGGLE_BUTTONS_RANK[3]);
		boolean rankingCombinationOk= false;

		if (numberOfPlayerPresent == 3) {
			for (int i = 0; i < ALLOWED_RANKING_3PLAYER.length; i++) {
				if (ALLOWED_RANKING_3PLAYER[i][0] == rank1Pressed
						&& ALLOWED_RANKING_3PLAYER[i][1] == rank2Pressed
						&& ALLOWED_RANKING_3PLAYER[i][2] == rank3Pressed) {
					rankingCombinationOk = true;
					break;
				}
			}
		} else {
			for (int i = 0; i < ALLOWED_RANKING_4PLAYER.length; i++) {
				if (ALLOWED_RANKING_4PLAYER[i][0] == rank1Pressed
						&& ALLOWED_RANKING_4PLAYER[i][1] == rank2Pressed
						&& ALLOWED_RANKING_4PLAYER[i][2] == rank3Pressed
						&& ALLOWED_RANKING_4PLAYER[i][3] == rank4Pressed) {
					rankingCombinationOk = true;
					break;
				}
			}
		}
		if (!rankingCombinationOk) {
			Toast.makeText(this, getResources().getString(R.string.text_invalidCombination), Toast.LENGTH_LONG).show();
		}

		return rankingCombinationOk;
	}

	private int getNumberOfButtonsPressed(int...ids) {
		int numberPressed = 0;
		for (int id : ids) {
			if (findViewById(id, ToggleButton.class).isChecked()) {
				numberPressed++;
			}
		}

		return numberPressed;
	}

	private void resetCounter() {
		for (int player = 0; player < NUM_PLAYER; player++) {
			for (int rank = 0; rank < NUM_PLAYER; rank++) {
				findViewById(TEXT_VIEW_COUNT[player][rank], TextView.class).setText("");
			}
			findViewById(TEXT_VIEW_SUM[player], TextView.class).setText("0");
			findViewById(TEXT_VIEW_OLD_ACC_BALANCE[player], TextView.class).setText("");
			findViewById(TEXT_VIEW_AMOUNT[player], TextView.class).setText("");
			findViewById(TEXT_VIEW_PAYMENT[player], TextView.class).setText("");
			findViewById(TEXT_VIEW_NEW_ACC_BALANCE[player], TextView.class).setText("");
		}
	}

	private void rewriteToggleButtons() {
		for (int player = 0; player < NUM_PLAYER; player++) {
			for (int rank = 0; rank < NUM_PLAYER; rank++) {
				rewriteToggleButton(TOGGLE_BUTTONS_PLAYER[player][rank], LABEL_RANK[rank], rankCounter[player][rank]);
			}
		}
	}

	private void rewriteToggleButton(int id, int label, int value) {
		findViewById(id, ToggleButton.class).setText(getResources().getString(label, points[value]));
		findViewById(id, ToggleButton.class).setTextOn(getResources().getString(label, points[value]));
		findViewById(id, ToggleButton.class).setTextOff(getResources().getString(label, points[value]));
	}

	@SuppressWarnings("unchecked")
	private <T extends View> T findViewById(int id, Class<T> clazz) {
		return (T)findViewById(id);
	}

	private String getStringPreference(String key) {
		return preferences.getString(key, "");
	}

	private int getIntPreference(String key) {
		return Integer.parseInt(getStringPreference(key));
	}

	private double getDoublePreference(String key) {
		return Double.parseDouble(getStringPreference(key));
	}

	private String createRestoreString() {
		StringBuffer buf = new StringBuffer();

		// Item 0: playerPresent (0 = false, 1 = true)
		for (int player = 0; player < NUM_PLAYER; player++) {
			buf.append(playerPresent[player] ? "1" : "0");
		}
		buf.append(";");
		// Item 1: numberOfPlayerPresent
		buf.append(numberOfPlayerPresent).append(";");
		// Item 2: gameCounter
		buf.append(gameCounter).append(";");
		// Item 3: currentPlayer
		buf.append(currentPlayer).append(";");
		// Item 4: rankCounter (Example: 1/2/3/4#2/4/6/8#3/6/9/12#4/8/12/16)
		for (int player = 0; player < NUM_PLAYER; player++) {
			for (int rank = 0; rank < NUM_PLAYER; rank++) {
				buf.append(rankCounter[player][rank]);
				if (rank < (NUM_PLAYER - 1)) {
					buf.append("/");
				}
			}
			if (player < NUM_PLAYER - 1) {
				buf.append("#");
			}
		}
		buf.append(";");
		// Item 5: historyItem (Example: 11/12/13/14#21/22/23/24#31/32/33/34)
		for (int[] historyItem : history) {
			for (int player = 0; player < NUM_PLAYER; player++) {
				buf.append(historyItem[player]);
				if (player < NUM_PLAYER - 1) {
					buf.append("/");
				}
			}
			buf.append("#");
		}

		return buf.substring(0, buf.length() - 1);
	}

	private void parseRestoreString(String restoreString) {
		String[] restoreItems = restoreString.split(";");

		// Item 0: playerPresent (0 = false, 1 = true)
		for (int player = 0; player < NUM_PLAYER; player++) {
			playerPresent[player] = restoreItems[0].charAt(player) == '1' ? true : false;
		}
		// Item 1: numberOfPlayerPresent
		numberOfPlayerPresent = Integer.parseInt(restoreItems[1]);
		// Item 2: gameCounter
		gameCounter = Integer.parseInt(restoreItems[2]);
		// Item 3: currentPlayer
		currentPlayer = Integer.parseInt(restoreItems[3]);
		// Item 4: rankCounter (Example: 1/2/3/4#2/4/6/8#3/6/9/12#4/8/12/16)
		String[] playerItems = restoreItems[4].split("#");
		for (int player = 0; player < NUM_PLAYER; player++) {
			String[] rankItems = playerItems[player].split("/");
			for (int rank = 0; rank < NUM_PLAYER; rank++) {
				rankCounter[player][rank] = Integer.parseInt(rankItems[rank]);
			}
		}
		// Item 5: historyItem (Example: 11/12/13/14#21/22/23/24#31/32/33/34)
		playerItems = restoreItems[5].split("#");
		history.clear();
		for (String playerItem : playerItems) {
			String[] rankItems = playerItem.split("/");
			int[] historyItem = new int[NUM_PLAYER];
			for (int player = 0; player < NUM_PLAYER; player++) {
				historyItem[player] = Integer.parseInt(rankItems[player]);
			}
			history.add(historyItem);
		}
	}
} 
